package org.ymf.service.impl;
import java.util.ArrayList;
import java.util.stream.Collectors;
import java.util.Map;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import javax.annotation.Resource;
import org.ymf.dao.UserEsDao;
import org.ymf.entity.UserEs;
import com.alibaba.excel.EasyExcel;
import com.github.pagehelper.PageInfo;
import com.github.pagehelper.PageHelper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.layuiframework.stereotype.exception.ThrowUtils;
import org.layuiframework.stereotype.vo.ResultCode;
import org.ymf.entity.User;
import org.ymf.mapper.UserMapper;
import org.ymf.service.UserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.ymf.vo.UserVo;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import org.layuiframework.stereotype.annotation.ImportFromFile;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;
import java.util.List;

/**
 * <p>
 * 用户 服务实现类
 * </p>
 *
 * @author Malphite
 * @since 2023-08-03
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Resource
    ElasticsearchRestTemplate elasticsearchRestTemplate;

    @Resource
    UserEsDao userEsDao;

    @Override
    public PageInfo<User> pageUser(UserVo vo){
        PageHelper.startPage(vo.getPage(), vo.getLimit());
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.like(StringUtils.hasLength(vo.getName()), "userName" , vo.getName());
        if(null != vo.getEndTime()) vo.setEndTime(new Date(vo.getEndTime().getTime() + 24 * 60 * 60 * 1000));
        queryWrapper.ge(null != vo.getStartTime(), "updateTime", vo.getStartTime());
        queryWrapper.le(null != vo.getEndTime(), "updateTime", vo.getEndTime());
        queryWrapper.orderByDesc(" updateTime ");
        List<User> dtos = this.list(queryWrapper);
        return new PageInfo(dtos);
    }

    @Override
    public List<User> listUser(UserVo vo){
        if(null != vo.getEndTime()) vo.setEndTime(new Date(vo.getEndTime().getTime() + 24 * 60 * 60 * 1000));
        return this.list(new QueryWrapper<User>()
            .like(StringUtils.hasLength(vo.getName()), "userName" , vo.getName())
            .ge(null != vo.getStartTime(), "updateTime", vo.getStartTime())
            .le(null != vo.getEndTime(), "updateTime", vo.getEndTime())
            .orderByDesc(" updateTime ")
        );
    }

    @ImportFromFile
    @Override
    public List<User> excelUser(MultipartFile file, List<User> objects, HttpServletRequest request){
        for (User user: objects) {
            // TODO 在这里修改实体类的信息
            user.setId(null);
        }
        return objects;
    }

    @Override
    public boolean addUser(User user, HttpServletRequest request){
        // TODO 追加信息，比如从请求对象中将用户信息取出来放入对象中
        // user.setCreateuser("");
        // 保存信息,如果失败抛出异常去处理
        ThrowUtils.throwIf(!this.save(user), ResultCode.NETERROR);
        return true;
    }

    @Override
    public boolean updateUser(User user){
        // 保存信息,如果失败抛出异常去处理
        ThrowUtils.throwIf(!this.updateById(user), ResultCode.NETERROR);
        return true;
    }

    @Override
    public boolean deleteUser(User user){
        // 保存信息,如果失败抛出异常去处理
        ThrowUtils.throwIf(!this.removeById(user), ResultCode.NETERROR);
        return true;
    }

    @Override
    public void exportUser(UserVo vo, HttpServletResponse response) throws IOException {
        response.setHeader("content-Type", "application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        // TODO 修改excel文件标题
        String title = "测试";
        // TODO 修改excel文件名称
        String filename = java.net.URLEncoder.encode(title, "UTF-8") + ".xlsx";
        // TODO 修改excel文件sheet名称
        String sheetname = "sheet1";
        response.setHeader("Content-Disposition", "attachment;filename=" + filename);
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.like(StringUtils.hasLength(vo.getName()), "userName" , vo.getName());
        if(null != vo.getEndTime()) vo.setEndTime(new Date(vo.getEndTime().getTime() + 24 * 60 * 60 * 1000));
        queryWrapper.ge(null != vo.getStartTime(), "updateTime", vo.getStartTime());
        queryWrapper.le(null != vo.getEndTime(), "updateTime", vo.getEndTime());
        queryWrapper.orderByDesc(" updateTime ");
        List<User> exports = this.list(queryWrapper);
        ServletOutputStream outputStream = response.getOutputStream();
        EasyExcel.write(outputStream, User.class).head(User.class)
            .sheet(sheetname)
            .useDefaultStyle(true).relativeHeadRowIndex(2).doWrite(exports);
        outputStream.flush();
    }

    @Override
    public PageInfo<User> pageUserEs(UserVo vo){
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        SortBuilder sortBuilder = SortBuilders.scoreSort();
        if(StringUtils.hasLength(vo.getName()))
            boolQueryBuilder.must(QueryBuilders.multiMatchQuery(vo.getName(),"userAccount","userPassword","userName","userAvatar","userRole"));
        if(null != vo.getEndTime()){
            vo.setEndTime(new Date(vo.getEndTime().getTime() + 24 * 60 * 60 * 1000));
            boolQueryBuilder.must(QueryBuilders.rangeQuery("updateTime").to(vo.getEndTime()));
        }
        if(null != vo.getStartTime())
            boolQueryBuilder.must(QueryBuilders.rangeQuery("updateTime").from(vo.getStartTime()));
        // sortBuilder = SortBuilders.fieldSort("updateTime");
        // sortBuilder.order(SortOrder.DESC);
        PageRequest pageRequest = PageRequest.of(vo.getPage(), vo.getLimit());
        List<HighlightBuilder.Field> fields = new ArrayList<>();
        fields.add(new HighlightBuilder.Field("userAccount"));
        fields.add(new HighlightBuilder.Field("userPassword"));
        fields.add(new HighlightBuilder.Field("userName"));
        fields.add(new HighlightBuilder.Field("userAvatar"));
        fields.add(new HighlightBuilder.Field("userRole"));
        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(boolQueryBuilder).withPageable(pageRequest).withSorts(sortBuilder).withHighlightFields(fields).build();
        SearchHits<UserEs> searchHits = elasticsearchRestTemplate.search(searchQuery, UserEs.class);
        PageInfo<User> page = new PageInfo<>();
        page.setTotal(searchHits.getTotalHits());
        List<User> resourceList = new ArrayList<>();
        if (searchHits.hasSearchHits()) {
            List<SearchHit<UserEs>> searchHitList = searchHits.getSearchHits();
            Map<Long, List<SearchHit<UserEs>>> searchHitMap = searchHitList.stream().collect(Collectors.groupingBy(searchHit -> searchHit.getContent().getId()));
            List<Long> userIdList = searchHitList.stream().map(searchHit -> searchHit.getContent().getId()).collect(Collectors.toList());
            // 从数据库中取出更完整的数据
            List<User> userList = baseMapper.selectBatchIds(userIdList);
            if (userList != null) {
                Map<Long, List<User>> idUserMap = userList.stream().collect(Collectors.groupingBy(User :: getId));
                userIdList.forEach(userId -> {
                    if (idUserMap.containsKey(userId)) {
                        User user = idUserMap.get(userId).get(0);
                        String highlightContent = searchHitMap.get(userId).get(0).getHighlightFields().values().stream().map(m -> m.get(0)).collect(Collectors.joining("|"));
                        user.setElasticsearchHintcontent(highlightContent);
                        user.setElasticsearchScore((double) searchHitMap.get(userId).get(0).getScore());
                        resourceList.add(user);
                    } else {
                        // 从 es 清空 db 已物理删除的数据
                        String delete = elasticsearchRestTemplate.delete(String.valueOf(userId), UserEs.class);
                    }
                });
            }
        }
        page.setList(resourceList);
        return page;
    }

}
